home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Risc World 3
/
Risc World 3.iso
/
SOFTWARE
/
ISSUE2
/
PD
/
VINCE
/
!ViNCe
/
c
/
tight16
< prev
next >
Wrap
Text File
|
2002-03-10
|
10KB
|
373 lines
/*
* Copyright (C) 2000 Const Kaplinsky. All Rights Reserved.
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
/*
* tight.c - handle ``tight'' encoding.
*
* This file shouldn't be compiled directly. It is included multiple
* times by rfbproto.c, each time with a different definition of the
* macro BPP. For each value of BPP, this file defines a function
* which handles an zlib encoded rectangle with BPP bits per pixel.
*
*/
#define TIGHT_MIN_TO_COMPRESS 12
#ifndef RGB_TO_PIXEL
#define RGB_TO_PIXEL(bpp,r,g,b) \
((CARD16)(r) & myFormat.redMax) << myFormat.redShift | \
((CARD16)(g) & myFormat.greenMax) << myFormat.greenShift | \
((CARD16)(b) & myFormat.blueMax) << myFormat.blueShift;
#define RGB24_TO_PIXEL32(r,g,b) \
((CARD32)(r) & 0xFF) << myFormat.redShift | \
((CARD32)(g) & 0xFF) << myFormat.greenShift | \
((CARD32)(b) & 0xFF) << myFormat.blueShift;
#endif
/* Type declarations */
typedef void (*filterPtr16)(int, CARD16 *);
/* Prototypes */
static int InitFilterCopy16 (int rw, int rh);
static int InitFilterPalette16 (int rw, int rh);
static int InitFilterGradient16 (int rw, int rh);
static void FilterCopy16 (int numRows, CARD16 *destBuffer);
static void FilterPalette16 (int numRows, CARD16 *destBuffer);
static void FilterGradient16 (int numRows, CARD16 *destBuffer);
/* Definitions */
static Bool HandleTight16 (int rx, int ry, int rw, int rh) {
CARD16 fill_colour;
CARD8 comp_ctl;
CARD8 filter_id;
filterPtr16 filterFn;
z_streamp zs;
char *buffer2;
int err, stream_id, bitsPixel;
int bufferSize, rowSize, numRows, rowsProcessed, extraBytes;
int compressedLen, portionLen;
if (!ReadFromRFBServer((char *)&comp_ctl, 1))
return False;
/* Flush zlib streams if we are told by the server to do so. */
for (stream_id = 0; stream_id < 4; stream_id++) {
if ((comp_ctl & 1) && zlibStreamActive[stream_id]) {
if (inflateEnd (&zlibStream[stream_id]) != Z_OK &&
zlibStream[stream_id].msg != NULL)
fprintf(stderr, "inflateEnd: %s\n", zlibStream[stream_id].msg);
zlibStreamActive[stream_id] = False;
}
comp_ctl >>= 1;
}
/* Handle solid rectangles. */
if (comp_ctl == rfbTightFill) {
if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour)))
return False;
// gcv.foreground = fill_colour;
display_fillrectangle(rx, ry, rw, rh, fill_colour);
return True;
}
/* Quit on unsupported subencoding value. */
if (comp_ctl > rfbTightMaxSubencoding) {
fprintf(stderr, "Tight encoding: bad subencoding value received.\n");
return False;
}
/*
* Here primary compression mode handling begins.
* Data was processed with optional filter + zlib compression.
*/
/* First, we should identify a filter to use. */
if ((comp_ctl & rfbTightExplicitFilter) != 0) {
if (!ReadFromRFBServer((char*)&filter_id, 1))
return False;
switch (filter_id) {
case rfbTightFilterCopy:
filterFn = FilterCopy16;
bitsPixel = InitFilterCopy16(rw, rh);
break;
case rfbTightFilterPalette:
filterFn = FilterPalette16;
bitsPixel = InitFilterPalette16(rw, rh);
break;
case rfbTightFilterGradient:
filterFn = FilterGradient16;
bitsPixel = InitFilterGradient16(rw, rh);
break;
default:
fprintf(stderr, "Tight encoding: unknown filter code received.\n");
return False;
}
} else {
filterFn = FilterCopy16;
bitsPixel = InitFilterCopy16(rw, rh);
}
if (bitsPixel == 0) {
fprintf(stderr, "Tight encoding: error receiving palette.\n");
return False;
}
/* Determine if the data should be decompressed or just copied. */
rowSize = (rw * bitsPixel + 7) / 8;
if (rh * rowSize < TIGHT_MIN_TO_COMPRESS) {
if (!ReadFromRFBServer((char*)buffer, rh * rowSize))
return False;
buffer2 = &buffer[TIGHT_MIN_TO_COMPRESS * 4];
filterFn(rh, (CARD16 *)buffer2);
display_raw(rx, ry, rw, rh, buffer2, 0);
// CopyDataToScreen(buffer2, rx, ry, rw, rh);
return True;
}
/* Read the length (1..3 bytes) of compressed data following. */
compressedLen = (int)ReadCompactLen();
if (compressedLen <= 0) {
fprintf(stderr, "Incorrect data received from the server.\n");
return False;
}
/* Now let's initialize compression stream if needed. */
stream_id = comp_ctl & 0x03;
zs = &zlibStream[stream_id];
if (!zlibStreamActive[stream_id]) {
zs->zalloc = Z_NULL;
zs->zfree = Z_NULL;
zs->opaque = Z_NULL;
err = inflateInit(zs);
if (err != Z_OK) {
if (zs->msg != NULL)
fprintf(stderr, "InflateInit error: %s.\n", zs->msg);
return False;
}
zlibStreamActive[stream_id] = True;
}
/* Read, decode and draw actual pixel data in a loop. */
bufferSize = BUFFER_SIZE * bitsPixel / (bitsPixel + 16) & 0xFFFFFFFC;
buffer2 = &buffer[bufferSize];
if (rowSize > bufferSize) {
/* Should be impossible when BUFFER_SIZE >= 16384 */
fprintf(stderr, "Internal error: incorrect buffer size.\n");
return False;
}
rowsProcessed = 0;
extraBytes = 0;
while (compressedLen > 0) {
if (compressedLen > ZLIB_BUFFER_SIZE)
portionLen = ZLIB_BUFFER_SIZE;
else
portionLen = compressedLen;
if (!ReadFromRFBServer((char*)zlib_buffer, portionLen))
return False;
compressedLen -= portionLen;
zs->next_in = (Bytef *)zlib_buffer;
zs->avail_in = portionLen;
do {
zs->next_out = (Bytef *)&buffer[extraBytes];
zs->avail_out = bufferSize - extraBytes;
err = inflate(zs, Z_SYNC_FLUSH);
if (err != Z_OK && err != Z_STREAM_END) {
if (zs->msg != NULL)
fprintf(stderr, "Inflate error: %s.\n", zs->msg);
return False;
}
numRows = (bufferSize - zs->avail_out) / rowSize;
filterFn(numRows, (CARD16 *)buffer2);
extraBytes = bufferSize - zs->avail_out - numRows * rowSize;
if (extraBytes > 0)
memcpy(buffer, &buffer[numRows * rowSize], extraBytes);
display_raw(rx, ry + rowsProcessed, rw, numRows, buffer2, 0);
// CopyDataToScreen(buffer2, rx, ry + rowsProcessed, rw, numRows);
rowsProcessed += numRows;
}
while (zs->avail_out == 0);
}
if (rowsProcessed != rh) {
fprintf(stderr, "Incorrect number of scan lines after decompression.\n");
return False;
}
return True;
}
/*----------------------------------------------------------------------------
*
* Filter stuff.
*
*/
/*
The following variables are defined in rfbproto.c:
static Bool cutZeros;
static int rectWidth, rectColors;
static CARD8 tightPalette[256*4];
static CARD8 tightPrevRow[2048*3*sizeof(CARD16)];
*/
static int
InitFilterCopy16 (int rw, int rh)
{
rectWidth = rw;
return 16;
}
static void
FilterCopy16 (int numRows, CARD16 *dst)
{
memcpy (dst, buffer, numRows * rectWidth * (16 / 8));
}
static int
InitFilterGradient16 (int rw, int rh)
{
int bits;
bits = InitFilterCopy16(rw, rh);
if (cutZeros)
memset(tightPrevRow, 0, rw * 3);
else
memset(tightPrevRow, 0, rw * 3 * sizeof(CARD16));
return bits;
}
static void
FilterGradient16 (int numRows, CARD16 *dst)
{
int x, y, c;
CARD16 *src = (CARD16 *)buffer;
CARD16 *thatRow = (CARD16 *)tightPrevRow;
CARD16 thisRow[2048*3];
CARD16 pix[3];
CARD16 max[3];
int shift[3];
int est[3];
max[0] = myFormat.redMax;
max[1] = myFormat.greenMax;
max[2] = myFormat.blueMax;
shift[0] = myFormat.redShift;
shift[1] = myFormat.greenShift;
shift[2] = myFormat.blueShift;
for (y = 0; y < numRows; y++) {
/* First pixel in a row */
for (c = 0; c < 3; c++) {
pix[c] = (CARD16)((src[y*rectWidth] >> shift[c]) + thatRow[c] & max[c]);
thisRow[c] = pix[c];
}
dst[y*rectWidth] = RGB_TO_PIXEL(16, pix[0], pix[1], pix[2]);
/* Remaining pixels of a row */
for (x = 1; x < rectWidth; x++) {
for (c = 0; c < 3; c++) {
est[c] = (int)thatRow[x*3+c] + (int)pix[c] - (int)thatRow[(x-1)*3+c];
if (est[c] > (int)max[c]) {
est[c] = (int)max[c];
} else if (est[c] < 0) {
est[c] = 0;
}
pix[c] = (CARD16)((src[y*rectWidth+x] >> shift[c]) + est[c] & max[c]);
thisRow[x*3+c] = pix[c];
}
dst[y*rectWidth+x] = RGB_TO_PIXEL(16, pix[0], pix[1], pix[2]);
}
memcpy(thatRow, thisRow, rectWidth * 3 * sizeof(CARD16));
}
}
static int
InitFilterPalette16 (int rw, int rh)
{
// int i;
CARD8 numColors;
// CARD16 *palette = (CARD16 *)tightPalette;
rectWidth = rw;
if (!ReadFromRFBServer((char*)&numColors, 1))
return 0;
rectColors = (int)numColors;
if (++rectColors < 2)
return 0;
if (!ReadFromRFBServer((char*)&tightPalette, rectColors * (16 / 8)))
return 0;
return (rectColors == 2) ? 1 : 8;
}
static void
FilterPalette16 (int numRows, CARD16 *dst)
{
int x, y, b, w;
CARD8 *src = (CARD8 *)buffer;
CARD16 *palette = (CARD16 *)tightPalette;
if (rectColors == 2) {
w = (rectWidth + 7) / 8;
for (y = 0; y < numRows; y++) {
for (x = 0; x < rectWidth / 8; x++) {
for (b = 7; b >= 0; b--)
dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
}
for (b = 7; b >= 8 - rectWidth % 8; b--) {
dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
}
}
} else {
for (y = 0; y < numRows; y++)
for (x = 0; x < rectWidth; x++)
dst[y*rectWidth+x] = palette[(int)src[y*rectWidth+x]];
}
}